package il.technion.cs236369.webserver;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Socket;

import org.apache.http.HttpException;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpVersion;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.protocol.HttpDateGenerator;

/**
 * this class handles all responses to the client 
 *
 */
public class HttpResponser
{
	private BasicHttpParams params;

	/**
	 * Initialises an HttpResponser with basic http parameters
	 */
	public HttpResponser()
	{
		params = new BasicHttpParams();
		params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
		params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "UTF-8");
		params.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 512 * 1024);
	}

	/**
	 * Receives the connection entities and sends an error to client with
	 * 	given code, reason and message
	 * Closes the connection and socket after it's done
	 * @param socket - the socket to send the message on
	 * @param statuscode - the status code of the message
	 * @param reason - the reason for the status
	 * @param message - the message to finally include
	 */
	public void sendErrorResponse(Socket socket, int statuscode, 
									String reason, String message)
	{
		DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
		
		try
		{
			conn.bind(socket, params);
			BasicHttpResponse response = buildHttpResponse(statuscode,reason,message);
			conn.sendResponseHeader(response);
			conn.sendResponseEntity(response);
		} 
		catch (IOException | HttpException e)
		{
			if (e instanceof HttpException)
			{
				System.err.println("failed to create httpserverconnection");
			}
			if (e instanceof IOException)
			{
				System.err.println("connection open, but failed to recieve request");
			}
			e.printStackTrace();
		}
		finally
		{
			if (conn != null)
			{
				try
				{
					conn.close();
					socket.close();
				} 
				catch (IOException e )
				{
					System.err.println("failed to close connection or socket");
					e.printStackTrace();
				}		
			}
		}
	}

	/**
	 * Creates a response with the desired content, does not 
	 * 	close the socket/connection when done
	 *  returns a response
	 * @param statuscode - The status code of the response
	 * @param rfcReason - the reason for the status code
	 * @param message - the message to finally include
	 * @return an HTTP response with the included code, reason and message
	 * @throws UnsupportedEncodingException
	 */
	private BasicHttpResponse buildHttpResponse(int statuscode, 
												String rfcReason, 
												String message)
												throws UnsupportedEncodingException
	{
		//Creating a response page with the error response
		BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,
															statuscode,
															rfcReason);
		response.setParams(params);
		
		//creating a date in the correct format
		HttpDateGenerator dateGenerator = new HttpDateGenerator();
		String date = dateGenerator.getCurrentDate();
		response.setHeader(HttpHeaders.DATE, date);
		//response.setHeader(HttpHeaders.CONTENT_ENCODING, params.getParameter("HTTP_CONTENT_CHARSET").toString());
		response.setHeader(HttpHeaders.CONNECTION, "Close");
		response.setHeader(HttpHeaders.CONTENT_TYPE, "text/html");

		StringEntity content = errorContentBuilder(statuscode, rfcReason, message);
		
		if (content != null)
		{
			response.setHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(content.getContentLength()));
			response.setEntity(content);
		}
		
		return response;
	}

	/**
	 * Builds a standard error page with the desired message
	 * @param statusCode - The status code of the message
	 * @param rfcReason - The reason for the status
	 * @param msg - The message to finally include
	 * @return a String entity with the html code for the error message
	 */
	private StringEntity errorContentBuilder(int statusCode, 
												String rfcReason, 
												String msg)
	{
		String XHTML = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"" +
				"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" +
				"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
		String content = XHTML+"<html>" + "<head><title> Error " +
				statusCode + ": " + rfcReason + "</title></head><body><center><h1><font color=\"red\"> <p>" +
				"Error " + statusCode + ": " + rfcReason +	
				"</p><p>" + msg + "</p></font></h1></center></body></html>";
		try
		{
			return new StringEntity(content);
		} 
		catch (UnsupportedEncodingException e)
		{
			System.err.println("Cannot convert message to StringEntity");
			e.printStackTrace();
			return null;
		}
	}
}	

